/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.visionet.waveletData.web.service.account;

import java.io.Serializable;
import java.security.Key;

import javax.annotation.PostConstruct;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.codec.H64;
import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.visionet.waveletData.web.common.security.password.PwdEncryptor;
import com.visionet.waveletData.web.entity.account.User;

public class ShiroDbRealm extends AuthorizingRealm {

	protected AccountService accountService;

	/**
	 * 认证回调函数,登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		
		User user = accountService.findByLoginName(token.getUsername());
		
		
		if (user == null) return null;
		
//		if (user.getIsLock().equals(SysConstants.USER_ACTIVITY_DISABLED)) {
//			throw new DisabledAccountException();
//		}
//		
//		if(user.getRoleList()==null || user.getRoleList().isEmpty()){
//			throw new RestException("role can not be null!");
//		}
//		
//		if(user.getOrgId()==null){
//			throw new RestException("organization can not be null!");
//		}

		String secName = null;
		
		ShiroUser shiroUser = new ShiroUser(user.getId(),user.getUser_name(),user.getCompany_id());
				
//		if(user.getSecId()!=null&&user.getIsLockSec()==0){
//			User sec = accountService.getUser(user.getSecId());
//			if(sec!=null) secName = sec.getAliasName();
//		}
		
//        ShiroUser shiroUser = new ShiroUser(user.getId(),
//                user.getAliasName(), user.getLoginName(), user.getOrgId(),
//                user.getOrgName(), user.getIsLock(), user.getLastLogin(),
//                user.getRoleList(), user.getIsLockSec(), user.getSecId(),
//                new String(token.getPassword()), secName,
//                "",UserInfoService.getUserLocale(user.getId()));
//        if(Validator.isNotNull(user.getPasswordSalt()) && !user.getPasswordSalt().equals("0")){
//            byte[] salt = Encodes.decodeHex(user.getPasswordSalt());
//            return new SimpleAuthenticationInfo(shiroUser,user.getPassword(), ByteSource.Util.bytes(salt), getName());
//        }else{
//            return new SimpleAuthenticationInfo(shiroUser,user.getPassword(),getName());
//        }

        return new SimpleAuthenticationInfo(shiroUser,user.getPass_word(),getName());
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		User user = accountService.findByLoginName(shiroUser.userName);

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//		for (Role role : user.getRoleList()) {
//			//基于Role的权限信息
//			info.addRole(role.getName());
//			//基于Permission的权限信息
//			info.addStringPermissions(role.getPermissionList());
//		}
		
		return info;
	}
	

	/**
	 * 设定Password校验的Hash算法与迭代次数.
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(PwdEncryptor.PASSWORDS_ENCRYPTION_ALGORITHM);
		matcher.setHashIterations(PwdEncryptor.HASH_INTERATIONS);
		setCredentialsMatcher(matcher);
	}

	@Autowired
	public void setAccountService(AccountService accountService) {
		this.accountService = accountService;
	}

	/**
	 * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {
		private static final long serialVersionUID = -1373760761780840081L;
		public Long id;
		public String userName;
		public String companyId;
		
		public ShiroUser() {
			
		}
		
		public ShiroUser(Long id , String userName , String companyId) {
			this.id=id;
			this.userName=userName;
			this.companyId=companyId;
		}
		
		public Long getId() {
			return id;
		}

		public void setId(Long id) {
			this.id = id;
		}

		public String getUserName() {
			return userName;
		}

		public void setUserName(String userName) {
			this.userName = userName;
		}

		public String getCompanyId() {
			return companyId;
		}

		public void setCompanyId(String companyId) {
			this.companyId = companyId;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return userName;
		}

		/**
		 * 重载hashCode,只计算loginName;
		 */
		@Override
		public int hashCode() {
			return Objects.hashCode(userName);
		}

		/**
		 * 重载equals,只计算loginName;
		 */
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			ShiroUser other = (ShiroUser) obj;
			if (userName == null) {
				if (other.userName != null)
					return false;
			} else if (!userName.equals(other.userName))
				return false;
			return true;
		}
	}
//	public static class ShiroUser implements Serializable {
//		private static final long serialVersionUID = -1373760761780840081L;
//		public Long id;
//		public String loginName;
//		public String aliasName;
//		
//		public Long orgId;
//		public String orgName;
//		
////		public String email;
//		public Integer isLock;
//		public Integer isLockSec;
//		public Long secId;
//		public Date lastLogin;
//		public Set<Role> roleList ; 
//		private String plainPassword;
//		public String secName;
//		public String userImgUrl;
//		public String locale;
//
//		public ShiroUser(String loginName) {
//			this.loginName = loginName;
//		}
//		
//		public ShiroUser(Long id, String loginName) {
//			this.id = id;
//			this.loginName = loginName;
//		}
//		
//		
//		public ShiroUser(Long id, String aliasName,String loginName,Long orgId,String orgName,Integer isLock,
//				Date lastLogin,Set<Role> roleList,Integer isLockSec,Long secId,String plainPassword,
//				String secName,String userImgUrl,String locale) {
//			this.id = id;
//			this.aliasName = aliasName;
//			this.loginName = loginName;
//			this.orgId = orgId;
//			this.orgName = orgName;
//			this.isLock = isLock;
//			this.lastLogin = lastLogin;
//			this.roleList = roleList;
//			this.isLockSec = isLockSec;
//			this.secId=secId;
//			this.plainPassword = plainPassword;
//			this.secName = secName;
//			this.userImgUrl = userImgUrl;
//			if(locale!=null){
//				this.locale = locale;
//                setLoaclNull();
//			}
//			
//		}
//
//        private static void setLoaclNull(){
//            BaseController.DefaultLocale = null;
//        }
//
//		public Long getUserId() {
//			return this.id;
//		}
//		
//		public Long getOrgId() {
//			return this.orgId;
//		}
//		
//		public String getOrgName() {
//			return this.orgName;
//		}
//		
//		public String getName() {
//			return this.aliasName;
//		}
//		
//		public String getPlainPassword() {
//			return plainPassword;
//		}
//
//		public String getUserImgUrl(){
//			return userImgUrl;
//		}
//		public String getRoleNames() {
//			return Collections3.extractToString(roleList, "name", ", ");
//		}
//
//
//		/**
//		 * 本函数输出将作为默认的<shiro:principal/>输出.
//		 */
//		@Override
//		public String toString() {
//			return loginName;
//		}
//
//		/**
//		 * 重载hashCode,只计算loginName;
//		 */
//		@Override
//		public int hashCode() {
//			return Objects.hashCode(loginName);
//		}
//
//		/**
//		 * 重载equals,只计算loginName;
//		 */
//		@Override
//		public boolean equals(Object obj) {
//			if (this == obj)
//				return true;
//			if (obj == null)
//				return false;
//			if (getClass() != obj.getClass())
//				return false;
//			ShiroUser other = (ShiroUser) obj;
//			if (loginName == null) {
//				if (other.loginName != null)
//					return false;
//			} else if (!loginName.equals(other.loginName))
//				return false;
//			return true;
//		}
//	}
	 /**
     * base64进制加密
     *
     * @param password
     * @return
     */
    public static String encrytBase64(String password) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(password), "不能为空");
        byte[] bytes = password.getBytes();
        return Base64.encodeToString(bytes);
    }
    /**
     * base64进制解密
     * @param cipherText
     * @return
     */
    public static String decryptBase64(String cipherText) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(cipherText), "消息摘要不能为空");
        return Base64.decodeToString(cipherText);
    }
    /**
     * 16进制加密
     *
     * @param password
     * @return
     */
    public static String encrytHex(String password) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(password), "不能为空");
        byte[] bytes = password.getBytes();
        return Hex.encodeToString(bytes);
    }
    /**
     * 16进制解密
     * @param cipherText
     * @return
     */
    public static String decryptHex(String cipherText) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(cipherText), "消息摘要不能为空");
        return new String(Hex.decode(cipherText));
    }
    public static String generateKey()
    {
        AesCipherService aesCipherService=new AesCipherService();
        Key key=aesCipherService.generateNewKey();
        return Base64.encodeToString(key.getEncoded());
    }
    /**
     * 对密码进行md5加密,并返回密文和salt，包含在User对象中
     * @param username 用户名
     * @param password 密码
     * @return 密文和salt
     */
//    public static User md5Password(String username,String password){
//        Preconditions.checkArgument(!Strings.isNullOrEmpty(username),"username不能为空");
//        Preconditions.checkArgument(!Strings.isNullOrEmpty(password),"password不能为空");
//        SecureRandomNumberGenerator secureRandomNumberGenerator=new SecureRandomNumberGenerator();
//        String salt= secureRandomNumberGenerator.nextBytes().toHex();
//        //组合username,两次迭代，对密码进行加密
//        String password_cipherText= new Md5Hash(password,username+salt,2).toBase64();
//        User user=new User();
//        user.setPassword(password_cipherText);
//        user.setSalt(salt);
//        user.setUsername(username);
//        return user;
//    }
	  public static void main(String[] args) {
		  String password1 =  new SimpleHash("SHA-1","123456",ByteSource.Util.bytes("admin"),1024).toHex(); 
		  System.out.println(password1);
		  
	        String password = "123456"; 
	        String cipherText = encrytHex(password);
	        System.out.println(password + "hex加密之后的密文是：" + cipherText);
	        String decrptPassword=decryptHex(cipherText);
	        System.out.println(cipherText + "hex解密之后的密码是：" + decrptPassword);
	        String cipherText_base64 = encrytBase64(password);
	        System.out.println(password + "base64加密之后的密文是：" + cipherText_base64);
	        String decrptPassword_base64=decryptBase64(cipherText_base64);
	        System.out.println(cipherText_base64 + "base64解密之后的密码是：" + decrptPassword_base64);
	        String h64=  H64.encodeToString(password.getBytes());
	        System.out.println(h64);
	        String salt="7road";
	        String cipherText_md5= new Md5Hash(password,salt,1024).toHex();
	        System.out.println(password+"通过md5加密之后的密文是："+cipherText_md5);
	        System.out.println(generateKey());
	        System.out.println("==========================================================");
	        AesCipherService aesCipherService=new AesCipherService();
	        aesCipherService.setKeySize(128);
	        Key key=aesCipherService.generateNewKey();
	        String aes_cipherText= aesCipherService.encrypt(password.getBytes(),key.getEncoded()).toHex();
	        System.out.println(password+" aes加密的密文是："+aes_cipherText);
	        String aes_mingwen=new String(aesCipherService.decrypt(Hex.decode(aes_cipherText),key.getEncoded()).getBytes());
	        System.out.println(aes_cipherText+" aes解密的明文是："+aes_mingwen);
	    } 
}
